package mapx

// Diff 比较 obj 和 parent，返回差异（如果没有差异则返回 nil）
func Diff(obj interface{}, parent interface{}, removeDefault bool) interface{} {
	switch v := obj.(type) {
	case nil:
		return nil
	case string:
		strA, okA := obj.(string)
		strB, okB := parent.(string)
		if !okA || !okB {
			return v
		}
		if strA == strB {
			return nil
		}
		return v
	case int:
		if pv, ok := parent.(int); ok {
			if v != pv {
				return v
			}
		} else {
			return v
		}

	case float64:
		if pv, ok := parent.(float64); ok {
			if v != pv {
				return v
			}
		} else {
			return v
		}

	case bool:
		if pv, ok := parent.(bool); ok {
			if v != pv && v {
				return v
			}
		} else if v {
			return v
		}

	case []interface{}: // 数组
		var tempArr []interface{}
		for i := 0; i < len(v); i++ {
			var b interface{}
			if parentArr, ok := parent.([]interface{}); ok && i < len(parentArr) {
				b = parentArr[i]
			}
			diff := Diff(v[i], b, removeDefault)
			if diff != nil {
				tempArr = append(tempArr, diff)
			}
		}
		if len(tempArr) > 0 {
			return tempArr
		} else {
			if removeDefault {
				return nil
			}
			return tempArr
		}

	case map[string]interface{}: // 对象
		tempObj := make(map[string]interface{})
		count := 0
		for k, a := range v {
			var b interface{}
			if parentMap, ok := parent.(map[string]interface{}); ok {
				b = parentMap[k]
			}
			diff := Diff(a, b, removeDefault)
			if diff != nil {
				tempObj[k] = diff
				count++
			}
		}

		if count > 0 {
			return tempObj
		} else {
			if removeDefault {
				return nil
			} else {
				if parent != nil {
					return nil
				}
				return tempObj
			}
		}
	}

	return nil
}
